home *** CD-ROM | disk | FTP | other *** search
- ;------------------------------------------------------------------------------
- ;Remote code for ApiHooks.
-
- ALIGN 4
-
- AlienScout :
-
- ASSUME EDI: PTR DWORD
-
- ;used local variables (related to AlienDLL), EDI points to AlienDLL
- VirtualQuery EQU [EDI][_VirtualQuery - AlienDLL]
- GetModuleFileNameA EQU [EDI][_GetModuleFileNameA - AlienDLL]
- LoadLibraryA EQU [EDI][_LoadLibraryA - AlienDLL]
- FreeLibrary EQU [EDI][_FreeLibrary - AlienDLL]
- GetProcAddress EQU [EDI][_GetProcAddress - AlienDLL]
- GetModuleHandleA EQU [EDI][_GetModuleHandleA - AlienDLL]
- VirtualProtect EQU [EDI][_VirtualProtect - AlienDLL]
- lstrcmpiA EQU [EAX] ;[_lstrcmpiA - AlienDLL]
- KERNEL32_ORD_0001 EQU [EDI][_KERNEL32_ORD_0001 - AlienDLL]
- ModCounter EQU [EDI][_VirtualQuery - AlienDLL]
- Modules EQU [EDI][_Modules - AlienDLL]
- ModExclude EQU [EDI][_GetModuleFileNameA - AlienDLL]
-
-
- AlienThread PROC
- PUSHp EAX, EBX, EBP, ESI, EDI
- CLD
- CALL Delta
- Delta:
- POP EDI
- ADD EDI, (AlienDLL - Delta) ;all is relative to AlienDLL
- ;make place on the stack
- SUB ESP, SIZEOF MEMORY_BASIC_INFORMATION+MAXMODULES*4
-
- SUB EBP, EBP
- CALL @F
-
- ;==============TxHandler
- MOV EDX, [ESP+12] ;context
- CALL Delta3
- Delta3:
- POP EAX
- ADD EDX, CONTEXT.regEip
-
- TxGPF01:
- ADD EAX, (GPF01-Delta3) ;fault at GPF01?
- CMP EAX, [EDX+CONTEXT.regEip-CONTEXT.regEip]
- LEA EAX, [EAX][CheckNextModule-GPF01] ;new EIP
- JE TxHFin ;yes -> go on at CheckNextModule
- TxGPF02:
- ADD EAX, (GPF02-CheckNextModule) ;fault at GPF02?
- CMP EAX, [EDX+CONTEXT.regEip-CONTEXT.regEip]
- LEA EAX, [EAX][NImpHook-GPF02]
- JE TxHFin ;yes -> go on at NImpHook
- TxHStandard:
- ADD EAX, (TDrWatson-NImpHook) ;unknown fault -> go on at DrWatson
- oMOV [EDX+CONTEXT.regEsp-CONTEXT.regEip], [ESP+8] ;new ESP
- TxHFin:
- MOV [EDX+CONTEXT.regEip-CONTEXT.regEip], EAX ;adjust EIP
- SUB EAX, EAX ;ExceptionContinueExecution
- RETN
- ;==============TxHandler
-
- @@:
- PUSH FS:(TEB PTR [EBP]).ExceptionList ;build xframe
- MOV FS:(TEB PTR [EBP]).ExceptionList, ESP
-
- ;==============EnumerateProcessModules
- ;build NULL terminated list of image bases of modules present in this process
-
- LEA ESI, [ESP+8] ;here will be module bases
- LEA EBX, [ESP+MAXMODULES*4+8] ;here will be place for VirtualQuery
- ASSUME EBX: PTR MEMORY_BASIC_INFORMATION
- MOV Modules, ESI
- NextMem:
- CMP ESI, EBX ;to many modules?
- JAE FinMod ;yes -> stop enumeration
- sWin32 VirtualQuery, EBP, EBX, SIZEOF MEMORY_BASIC_INFORMATION
- TEST EAX, EAX
- JE FinMod ;when VQ fails we're done (to high address)
- @@:
- MOV EBP, [EBX].BaseAddress
- sWin32 GetModuleFileNameA, EBP, ESI, 2 ;is there some module on the base address?
- TEST EAX, EAX
- JE @F ;no -> next address
- TEST EBP, EBP ;yes, but is it special case of NULL (= main module)?
- JE @F ;yes it was the special case -> next address
- MOV [ESI], EBP ;there is module, put down its image address
- LODSD ;ESI to the next prosition
- @@:
- ADD EBP, [EBX].RegionSize ;create new address
- JMP NextMem
- FinMod:
- AND DWORD PTR [ESI],0 ;NULL terminated list
- ASSUME EBX: NOTHING
- ;==============EnumerateProcessModules
-
- MOV EBX, EDI ;DllName or dynaimc hooks address
-
- AND ModExclude, 0 ;initialize pointer to image bases to
- ;exclude to NULL
- ;check for dynamic hooks
- ASSUME ESI : PTR API_HOOK
- MOV ESI, [EBX+4] ;pointer to dynamic hooks in this process
- CMP DWORD PTR [EBX], HOOKS_DYNAMIC
- JNE @F ;go Hooks.dll
- ;yes there are dynaimc hooks then UnhookAddresses
- ;can contain pointer to image bases to exclude
- PUSH [ESI].UnhookAddresses
- POP ModExclude
- JMP NewHook0 ;start with the next AH structure
-
- ;it is Hooks.dll
- @@:
- sWin32 GetModuleHandleA, EBX ;test if hooks.dll is present here
- TEST EAX, EAX
- JNE HANFailed ;fail if already present in this process
-
- sWin32 LoadLibraryA, EBX ;load hooks.dll
- TEST EAX, EAX
- JE @F ;HANFailed can't load it
-
- ;get address of GetApiHookChain
- MOV EBX, EAX
- LEA ECX, [EDI][GetAHC-AlienDLL]
- MOV ESI, GetProcAddress
- sWin32 ESI, EBX, ECX
- TEST EAX, EAX
- JE CheckAHC
- sWin32 EAX ;call GetApiHookChain
- JMP ProcFound
- CheckAHC:
- ;get address of ApiHookChain
- LEA ECX, [EDI][GetAHC+3-AlienDLL]
- sWin32 ESI, EBX, ECX
- TEST EAX, EAX
- JNE ProcFound
- ;get address of ORD_0001
- sWin32 ESI, EBX, 1
- TEST EAX, EAX
- @@:
- JE HANFailed ;hooks.dll doesn't export (Get)ApiHookChain and ordinal 1
- ProcFound:
- XCHG EAX, ESI ;ESI -> AH chain
-
- NextHook::
- AND ModCounter, 0 ;zero module counter
- MOV EBX, [ESI].ModuleExport
- CMP EBX, HOOKS_END ;if ModuleExport == HOOKS_END
- JE AllDone ;we're done
- sWin32 GetModuleHandleA, EBX ;get image base of ModuleExport
-
- COMMENT /* here was if ModuleExport is missing load it
- TEST EAX, EAX
- JNE @F
- sWin32 LoadLibraryA, EBX
- */
- TEST EAX, EAX
- NewHook0:
- JE NewHook ;ModuleExport is missing -> go next AH structure
- @@:
- XCHG EAX, EBX ;ModuleExport image base to EBX
-
- ;--------------------------------------------------------------------------------
- ;HOOK_BY_ADDRESS: import table of chosen modules is searched for occurence
- ;of address of API given by ApiNameOrOrd. If it is found it is replaced
- ;by HookAddress.
-
- TEST BYTE PTR [ESI].dwFlags, HOOK_BY_ADDRESS
- JE HookByExport ;user doesn't want this method
- sWin32 GetProcAddress, EBX, [ESI].ApiNameOrOrd
- TEST EAX, EAX
- JE HookByExport ;API doesn't exist go on with Export works
- CheckNextModule:
- PUSH EAX
- sWin32 xGetModuleHandleA ;get module for Import works
- TEST EAX, EAX
- XCHG EAX, EBX ;base to EBX
- POP EAX ;EAX == address of wanted API
- JE HookByExport ;no more modules
-
- GPF01: ;+CheckNextModule
- MOV EDX, [EBX+3CH] ;PE header start
- MOV EDX, [EDX+80H+EBX] ;import table start
- SUB ECX, ECX
-
- TEST EDX, EDX ;no import
- JE CheckNextModule ;next module
-
- ADD EDX, EBX ;edx = import table
- JMP @F
- sNextMod:
- ADD ECX, 14H ;next module entry
- @@:
- CMP DWORD PTR [EDX+ECX+0CH], 0 ;module name == NULL?
- JE CheckNextModule ;then next module
- MOV EBP, [EDX+ECX+10H] ;address list
- LEA EBP, [EBP+EBX-4] ;1st API address - 4
- sNextProc:
- CMP DWORD PTR [EBP+4], 0 ;address == NULL?
- JE sNextMod ;go next module entry
- CMP EAX, [EBP+4] ;is it wanted API address?
- LEA EBP, [EBP+4] ;to the next API address
- JNE sNextProc ;no cycle
-
- ;make [EBP] writeable
- PUSHp EAX, ECX, EDX ;save used registers
- PUSH EDX ;place for original attr.
- sWin32 VirtualProtectX, EBP, 4, PAGE_READWRITE, ESP
- TEST EAX, EAX
- POP EDX ;original attribute
- JE @NextImport ;VP failed
-
- CALL CheckUnhook ;check for saving original address
-
- MOV EAX, [ESI].HookAddress ;new api address
- MOV [EBP], EAX ;write it
-
- ;return old memory attribute
- PUSH EDX ;old atttribute
- sWin32 VirtualProtectX, EBP, 4, EDX, ESP
- POP EDX ;remove superlocal var.
- @NextImport:
- POPc EAX, ECX, EDX ;restore used registers
- JMP sNextProc ;go on with next api
- ;--------------------------------------------------------------------------------
- ;HOOK_BY_EXPORT: export table of ModuleExport is searched for occurence
- ;of relative address of API given by ApiNameOrOrd. If it is found it is replaced
- ;by relative HookAddress.
-
- HookByExport:
- TEST BYTE PTR [ESI].dwFlags, HOOK_EXPORT
- JE @F ;user doesn't want this method
- sWin32 GetModuleHandleA, [ESI].ModuleExport
- TEST EAX, EAX
- JE @F ;HookByImport ;ModuleExport is not present
- XCHG EAX, EBX
- MOV EBP, [ESI].ApiNameOrOrd
- MOV EDX, [EBX+3CH] ;PE header start
- MOV EDX, [EDX+78H+EBX] ;export table
- TEST EDX, EDX
- @@:
- JE GoToImport ;HookByImport ;no export table
- ADD EDX, EBX
- CMP EBP, 10000H ;ordinal# or name?
- JAE @F
- XCHG EAX, EBP ;eax = ordinal#
- SUB EAX, [EDX+10H] ;eax = ordinal# - ordinal base
- JMP ExportOrd
- @@:
- ;search for the name of wanted api
- PUSH EBX
- PUSH ESI
- PUSH EDI
- MOV ECX, [EDX+18H] ;amountofnames
- MOV ESI, [EDX+20H] ;addressofnames
- ADD ESI, EBX
- PUSH EDX
- @@:
- JECXZ NameSearchFinished ;nothing left to explore
- LODSD
- SUB EDI, EDI
- ASSUME EDI: PTR BYTE
- ADD EAX, EBX
- DEC ECX
- NextChar:
- MOV DL, [EAX+EDI] ;find matching API name
- CMP DL, [EBP+EDI] ;by comparing letters
- JNE @B ;no match go next name
- INC EDI
- TEST DL, DL
- JNE NextChar ;repeat until NULL character
- SUB EAX, EAX ;api found! -> EAX = NULL
- NameSearchFinished:
- POP EDX
- POP EDI
- ASSUME EDI: PTR DWORD
- POP ESI
- POP EBX
-
- TEST EAX, EAX
- JNE HookByImport ;EAX != NULL -> api not found
-
- SUB ECX, [EDX+18H] ;amountofnames
- MOV EAX, [EDX+24H] ;ordinals for names
- INC ECX
- NEG ECX
- ADD EAX, EBX
- MOVZX EAX, WORD PTR [ECX*2+EAX]
- ExportOrd:
- MOV ECX, EBX ;ecx = module base
- ADD ECX, [EDX+1CH]
- LEA EBP, [ECX+EAX*4] ;orig address
-
- ;make [EBP] writeable
- PUSH EDX
- sWin32 VirtualProtectX, EBP, 4, PAGE_READWRITE, ESP
- TEST EAX, EAX
- POP EDX ;orig settings
- GoToImport:
- JE HookByImport
-
- CALL CheckUnhook ;check for saving original address
-
- MOV EAX, [ESI].HookAddress ;new api address
- SUB EAX, EBX ;make it relative to module base
- MOV [EBP], EAX ;write it
-
- ;return old memory attribute
- PUSH EDX
- sWin32 VirtualProtectX, EBP, 4, EDX, ESP
- POP EDX
- ;go on with unbinding
- ;-do UNBIND----------------------------------------------------------
- ;If HOOK_EXPORT was used it is good in NT to break bonds of all newly
- ;loaded modules to ModuleExport otherwise HOOK_EXPORT would have
- ;no effect on such modules
-
- TEST BYTE PTR [ESI].dwFlags, HOOK_NO_UNBIND
- W9xJMP0::
- JMP HookByImport ;will be patched to JNE if OS == NT
- MOV EDX, FS:TEB.pPEB
- MOV ECX, (PEB PTR [EDX]).pProcParameters
- ADD ECX, PROCESS_PARAMETERS.pFirstModEntry0
- MOV EAX, [ECX] ;ECX == end of round queue, EAX== 1st module entry0
- JMP First0
- @@:
- ASSUME EAX: PTR PEB_MODULE_ENTRY0
- CMP [EAX].ImageBase, EBX
- JNE ThisIsNotModuleExport
- INC [EAX].ImageTimeStamp ;change time stamp, there will be no matches
- ThisIsNotModuleExport: ;and binding will fail
- MOV EAX, [EAX].pNextModEntry0
- First0:
- CMP EAX, ECX ;at the end of the queue?
- JNE @B ;no, try next module
- ASSUME EAX: NOTHING
- ;--------------------------------------------------------------------------------
- ;HOOK_IMPORT: import table of chosen modules is searched for occurence
- ;of API name matching to ApiNameOrOrd. If it is found it is replaced
- ;by HookAddress.
- HookByImport:
- TEST BYTE PTR [ESI].dwFlags, HOOK_IMPORT
- JE @F ;user doesn't want this method
- NImpHook:
- sWin32 xGetModuleHandleA ;get module (from list)
- TEST EAX, EAX
- @@:
- JE SkipImp ;no more modules
- XCHG EAX, EBX ;ebx = imag base
-
- GPF02: ;+NImpHook
- MOV EDX, [EBX+3CH] ;PE header start
- MOV EDX, [EDX+80H+EBX] ;import table start
-
- TEST EDX, EDX ;no import
- JE NImpHook
-
- SUB EDI, EDI
- ADD EDX, EBX ;edx = import table
- mNextMod:
- MOV EBP, [EDX+EDI+0CH] ;module names
- TEST EBP, EBP
- JE NImpHook ;no more module names
- ADD EBP, EBX
- ADD EDI, 14H
- PUSH EDX
- CALL Delta0
- Delta0:
- POP EAX
- ASSUME EAX: PTR DWORD
- ADD EAX, (_lstrcmpiA-Delta0)
- sWin32 lstrcmpiA, [ESI].ModuleExport, EBP ;compare module names
- TEST EAX, EAX
- POP EDX
- JNE mNextMod
-
- MOV EBP, [EDX+EDI-14H] ;proc names
- TEST EBP, EBP
- JE NImpHook ;SkipImp
- CMP EBP, [EDX+EDI-14H+10H] ;address list
- JE NImpHook ;SkipImp
-
- MOV EAX, [ESI].ApiNameOrOrd
- JMP @F
- pNextName:
- POP EDI
- POP EDX
- ADD EBP, 4
- @@:
- MOV ECX, [EBP+EBX]
- JECXZ mNextMod
-
- PUSH EDX
- PUSH EDI
- CMP EAX, 10000H ;ordinal#?
- JAE ImpByName
- TEST ECX, ECX
- JNS pNextName
- CMP AX, CX
- JE ImpSearchFinished
- JMP pNextName
- ImpByName:
- TEST ECX, ECX
- JS pNextName
- ADD ECX, EBX
- SUB EDI, EDI
- ASSUME EDI: PTR BYTE
- pNextChar:
- MOV DL, [EAX+EDI] ;compare api names
- CMP DL, [ECX+EDI+2]
- JNE pNextName
- INC EDI
- TEST DL, DL
- JNE pNextChar
- ImpSearchFinished:
- POP EDI
- ASSUME EDI: PTR DWORD
- POP EDX
- MOV EAX, [EDX+EDI-14H+10H]
- SUB EBP, [EDX+EDI-14H+00H]
- ADD EBP, EAX
- ADD EBP, EBX
- CALL Delta1
- Delta1:
- POP EDI
- ASSUME EDI: PTR DWORD
- LEA EDI, [EDI][AlienDLL-Delta1]
-
- ;make [EBP] writeable
- PUSH EDX
- sWin32 VirtualProtectX, EBP, 4, PAGE_READWRITE, ESP
- TEST EAX, EAX
- POP EDX ;orig settings
- JE @F ;NImpHook ;here should be loop to the next name
-
- CALL CheckUnhook
-
- MOV EAX, [ESI].HookAddress ;new api address
- MOV [EBP], EAX ;write it
- ;return old memory attribute
- PUSH EDX
- sWin32 VirtualProtectX, EBP, 4, EDX, ESP
- POP EDX
- ;here should be loop to the next name
- @@:
- JMP NImpHook
- ;--------------------------------------------------------------------------------
- SkipImp:
- NewHook:
- ADD ESI, SIZEOF API_HOOK ;go next AH structure
- JMP NextHook
-
- TDrWatson:: ;if exception
- HANFailed: ;or failed, go here
- oMOV EAX, ErrorRemoteExec ;return this error coed
- JMP @F
- AllDone:
- SUB EAX, EAX ;return ErrorSuccess
- @@:
- POP FS:TEB.ExceptionList ;remove xframe
- ADD ESP, SIZEOF MEMORY_BASIC_INFORMATION+MAXMODULES*4 +4 ;adjust ESP
- POPp EDI, ESI, EBP, EBX, ECX
- @Stop::
- DWORD 0, 0, 0 ;place reserved for RemoteExec
- AlienThread ENDP
-
- ;============================================================================
- VirtualProtectX PROC vpWhere, vpSize, vpAttrib, vpOrgAttrib
-
- PC_WRITEABLE EQU 00020000H
- PC_USER EQU 00040000H
- PC_PRESENT EQU 80000000H
- PC_STATIC EQU 20000000H
- PC_DIRTY EQU 08000000H
- _PageModifyPermissions EQU 0001000DH
-
- MOV EDX, vpWhere
- TEST EDX, EDX ;above 2GB?
- JNS @F ;no go VP
- SUB EAX, EAX ;else test for hard hooking
- TEST BYTE PTR [ESI].dwFlags, HOOK_HARD
- JE VPFail ;no hard hooks and above 2GB -> like VP failed
- SHR EDX, 12 ;address -> page#
- ;Win9x: change 1 page attrinutes to writeable
- sWin32 KERNEL32_ORD_0001, _PageModifyPermissions, EDX, 1, -1, PC_STATIC OR PC_USER OR PC_WRITEABLE
- INC EAX ;failed?
- JE VPFail ;yes
- @@:
- ;now can VP be used
- sWin32 VirtualProtect, vpWhere, vpSize, vpAttrib, vpOrgAttrib
- VPFail:
- RET
- VirtualProtectX ENDP
- ;============================================================================
- ;Check if user wants to get old api addresses and their storage addresses
-
- CheckUnhook PROC
- MOV ECX, [ESI].UnhookAddresses
- JECXZ @F ;it is empty -> fin
- ASSUME ECX:PTR API_UNHOOK
- MOV EAX, [ECX].CurNoAddr ;is current contents
- CMP EAX, [ECX].MaxNoAddr ;=> max contents
- JGE @F ;yes -> fin
- PUSH EDX
- INC [ECX].CurNoAddr ;++CurNoAddr
- MOV ECX, [ECX].WhereWhat
- ASSUME ECX:PTR ADDR_CONTENTS
- MOV EDX, [EBP] ;old api address
- ;remember storage address
- MOV [ECX+EAX*SIZEOF ADDR_CONTENTS].ReturnWhere, EBP
- ;remember old api address
- MOV [ECX+EAX*SIZEOF ADDR_CONTENTS].ReturnWhat, EDX
- POP EDX
- @@:
- RET
- ASSUME ECX:NOTHING
- CheckUnhook ENDP
- ;============================================================================
- ;Get module handle a) from list (made by VirtualQuery) if ModuleImport == ALL_MODULES
- ; or b) from standard GetModuleHandle(ModuleImport)
- ;but check if the returned image base is "on index" (list pointed by ModExclude)
- ;if it is there, try next module in the list.
-
- xGetModuleHandleA PROC
- CALL Delta6
- Delta6:
- POP EDI
- ASSUME EDI: PTR DWORD
- LEA EDI, [EDI][AlienDLL-Delta6]
-
- TryNextMod:
- MOV EAX, [ESI].ModuleImport
- MOV ECX, ModCounter ;index of module in Modules list
- INC EAX ;CMP EAX, ALL_MODULES
- JE @F
- DEC EAX ;CMP EAX, ALL_MODULES
- DEC ECX
- XCHG EAX, ECX
- JGE xGFail
- sWin32 GetModuleHandleA, ECX ;no ALL_MODULES -> pure GetModuleHandle
- JMP xGSuc
- @@: ;was ALL_MODULES
- MOV EAX, Modules ;head of list
- MOV EAX, [EAX+ECX*4] ;get the indexed module
- xGSuc:
- TEST EAX, EAX ;at the end of Modules list?
- JE xGFail ;yes -> return NULL
- INC ModCounter ;++index
- sWin32 CheckExclude ;check for exclusion of base in EAX
- JE TryNextMod ;excluded -> next module
- RET
- xGFail:
- AND ModCounter, EAX ;reset Mdules index
- RET
- xGetModuleHandleA ENDP
-
- CheckExclude PROC ;IN: EAX=ModuleBase
- MOV EDX, ModExclude
- TEST EDX, EDX
- JE AllowThisMod ;no exclude list
- @@:
- CMP DWORD PTR [EDX], NULL ;at the end of list?
- JE AllowThisMod ;yes -> module can go
- CMP EAX, [EDX]
- LEA EDX, [EDX+4]
- JNE @B ;next module to exclude
- SUB EAX, EAX ;found -> return NULL (==excluded)
- AllowThisMod:
- TEST EAX, EAX ;return ZF set if Module can go
- RET
- CheckExclude ENDP
- ;============================================================================
-
- ASSUME EAX :NOTHING
- ASSUME ECX :NOTHING
- ASSUME ESI :NOTHING
- ASSUME EDI :NOTHING
- GetAHC BYTE "GetApiHookChain",0
-
- ALIGN 4
-
- ;these dwords will be initialized in DllMain
- ;but after their contents was used (saves space in ApiHooks.dll)
-
- NewState LABEL TOKEN_PRIVILEGES
- _VirtualQuery DWORD 1
- dbLUID LABEL LUID
- _GetModuleFileNameA DWORD 0
- _LoadLibraryA DWORD 0
- _GetProcAddress DWORD SE_PRIVILEGE_ENABLED
-
- T32N LABEL SIGN
- sT32N EQU OFFSET T32N
- _GetModuleHandleA LABEL DWORD
- BYTE 'Thre'
- _VirtualProtect LABEL DWORD
- BYTE 'ad32'
- _lstrcmpiA LABEL DWORD
- BYTE 'Next'
- _KERNEL32_ORD_0001 LABEL DWORD
- BYTE 0
- NTDLL BYTE 'NTD'
- sNTDLL EQU OFFSET NTDLL
- _Modules LABEL DWORD
- BYTE 'LL.D'
- ALIGN 4
- AlienDLL LABEL ACHAR
- AlienSize0 EQU (($-AlienScout+3) AND NOT 3) ;pure block size, dword aligned
- AlienSize EQU (($-AlienScout+MAX_PATH+3) AND NOT 3) ;overall block size (with MAX_PATH), dword aligned
- BYTE 'LL',0
- ;------------------------------------------------------------------------------
-